local print = print

package.path = package.path..";./lib/?.lua"

require("wx")
require("iconv")
require("htk")

require("task")
require("taskmsg")
require("atcmd")
require("config")
require("contactsdb")

----global variable,avoid strict.lua error


----mainframe class extend
function mainframe_create_subtask(self)
    --register name 'main'
    local rc = task.register('main')
    assert(rc==0)
    --print("my id",task.id())
    
    --start atworker
    local id_atworker, err = task.create('atworker.lua')
    assert(id_atworker>0)
    self.id_atworker = id_atworker
    
    --it is weird,if there is not task.sleep(),
    --"task.find('atworker')" will fail,and often crash...
    task.sleep(150)
    --print(self.id_atworker,task.find('atworker'),task.isrunning(self.id_atworker))
    assert(task.isrunning(self.id_atworker))
    
    --[[tell atworker to find a phone connected COM
    local msg = 
    {
        msgtype = "SEARCH_CONNECTED_COM_REQ",
    }
    taskmsg.post(id_atworker,msg)
    ]]--
    
    --create conndetector
    local id_conndetector, err = task.create('conndetector.lua')
    assert(id_conndetector>0)
    self.id_conndetector = id_conndetector
    
    --refresh the controls enable or not
    mainframe_refresh_controls_enable(self)
end

function mainframe_refresh_controls_enable(self)
    local connected = (self.connected_rs232_port~="" and self.phone_init_finished)
    self.m_button_sendsms:Enable(connected and (not self.sms_too_long))
    self.m_button_smslog:Enable(connected)
    self.m_button_contacts:Enable(connected)
    self.m_textCtrl_phonenum:Enable(connected)
end

function send_AT_CMD_REQ_and_wait_CNF(msg)
    local msgback
    --here should use task name,if use id,luatask1.6.4 will crash
    taskmsg.post('atworker',msg)
    while(1) do
        msgback = coroutine.yield()
        if (msgback.msgtype == "AT_CMD_CNF" and (msgback.at_type == msg.at_type)) then
            return msgback
        end
    end
end

function mainframe_init_phone(self)
    --avoid wxlua bug,TODO
    local m_statusBar = self.m_statusBar
    local connected_rs232_port = self.connected_rs232_port

    local mainframe_import_all_contacts_co = self.import_all_contacts_co
    
    local function init_phone()
        --firstly set phone as PDU mode
        local msg = send_AT_CMD_REQ_and_wait_CNF
        {
            msgtype="AT_CMD_REQ",
            at_type="AT_CMGF_SET_PDU",
            at_cmd=atcmd.AT_CMGF_SET_PDU(),
            from = task.id(),
        }
        print("AT_CMGF_SET_PDU result:",atcmd.repr(msg.reply))
        
        --then get the model and IMEI,so we can identify the phone
        local msg = send_AT_CMD_REQ_and_wait_CNF
        {
            msgtype="AT_CMD_REQ",
            at_type="AT_CGMM",
            at_cmd=atcmd.AT_CGMM(),
            from = task.id(),
        }
        print("AT_CGMM result:",atcmd.repr(msg.reply))
        local function get_model_from_at_reply(reply)
            for k in string.gmatch(reply,"+CGMM:%s*([%a%d]+)") do
                return k
            end
            return ""
        end
        local model = get_model_from_at_reply(msg.reply)
        
        local msg = send_AT_CMD_REQ_and_wait_CNF
        {
            msgtype="AT_CMD_REQ",
            at_type="AT_CGSN",
            at_cmd=atcmd.AT_CGSN(),
            --timeout=2000,
            from = task.id(),
        }
        print("AT_CGSN result:",atcmd.repr(msg.reply))
        local function get_IMEI_from_at_reply(reply)
            for k in string.gmatch(reply,"(%d+)") do
                return k
            end
            return ""
        end
        local imei = get_IMEI_from_at_reply(tostring(msg.reply))
        
        self.phone_id = string.format("%s_%s",model,imei)
        print(self.phone_id)
        
        local status = string.format("connected: %s with %s",model,tostring(connected_rs232_port))
        m_statusBar:SetStatusText(status)
        
        --contactsdb init
        self.contactsdb = contactsdb.contactsdb:new({db_path=self.phone_id..".sqlite"})
        --TODO: I hate the wxlua'bug
        if self.contactsdb.cache then
            self.contactsdb:cache_defaultenc(self.config.os_default_encoding)
        end
        --print(prettytostring(self.contactsdb.cache))
        
        if self.contactsdb.cache == nil then
            --[[
            --ask if user want to import
            local import_contacts = wx.wxMessageBox("Do you want to import contacts from phone?",
                                    "Phonecom",
                                    wx.wxOK + wx.wxCANCEL + wx.wxICON_QUESTION,
                                    wx.NULL)
            if import_contacts==wx.wxOK then
                local contacts = mainframe_import_all_contacts_co(self)
                self.contactsdb:replace_cache(contacts)
            end
            --]]
            local contacts = mainframe_import_all_contacts_co(self)
            self.contactsdb:replace_cache(contacts)
        end
        print("contactsdlg",self.contactsdlg)
        
        self.phone_init_finished = true
    end
    mainframe_set_msgco_and_go(self,init_phone)
end

function mainframe_set_msgco_and_go(self,func)
    --create co
    local co = coroutine.create(func)
    self.msgco = co
    --go
    print("before go:",coroutine.status(self.msgco))
    local resume_ok,err = coroutine.resume(self.msgco)
    print(resume_ok,err)
    print("after go:",coroutine.status(self.msgco))
end

function mainframe_on_idle(self,event)
    --check if there is any message
    local msg,count
    count = 0
    msg = taskmsg.receive(10)
    repeat
        if msg~=nil then
            --print("receive msg:",atcmd.repr(msg))
            mainframe_msg_handle(self,msg)
        else
            --print("really idle...")
            -- if there is no msg,we handle msg until next timer timeout
            break
        end
        
        count = count +1
        --we take a break after 10 msg,so the UI can be update
        if count>=50 then break end
        
        --why 220? Because if there is continuous msg,we handle it
        --continuously.otherwise we will handle msg only 
        --everytime timer timeout.and 200 is atworker time unit,
        --it should a little longer then the time unit
        msg = taskmsg.receive(220)
    until msg==nil
    --print("timer:is runing:",self.msg_timer:IsRunning())
end

function mainframe_on_button_contacts(self,event)
    self.contactsdlg:ShowModal()
    --[[
    if self.contact_listbox:IsShown() then
        self.contact_listbox:Hide()
        self.m_panel_main:Layout()
    else
        local r = self.contactsdb:search_cache()
        self_contact_listbox:Set(r)
        
        self:Connect(self.contact_listbox:GetId(),
            wx.wxEVT_COMMAND_LISTBOX_SELECTED,
            function(event)
                local n,selections = self.contact_listbox:GetSelections()
                if n > 0 then
                    local i = selections[1]
                    --replace with selection
                    local w = self.m_textCtrl_phonenum:GetValue()
                    self.m_textCtrl_phonenum:SetValue(string.format("%s %s,",w,r[i+1]))
                    self.m_textCtrl_phonenum:SetInsertionPointEnd()
                end
                self.contact_listbox:Hide()
                self.m_panel_main:Layout()
                self:Disconnect(self.contact_listbox:GetId(),wx.wxEVT_COMMAND_LISTBOX_SELECTED)
                self.m_textCtrl_phonenum:SetFocus()
            end)
        
        self.contact_listbox:Show()
        self.m_panel_main:Layout()
    end
    --]]
end

function mainframe_on_button_smslog(self,event)
    self.smslogdlg:ShowModal()
end

function mainframe_on_button_sendsms(self,event)
    --sigh...to avoid wxlua bug.TODO:use "self."directly
    local m_textCtrl_phonenum = self.m_textCtrl_phonenum
    local m_textCtrl_sms = self.m_textCtrl_sms
    local m_comboBox_encoding = self.m_comboBox_encoding
    
    local function sendsms()
        local at1,at2 = atcmd.AT_CMGS_PDU(m_textCtrl_phonenum:GetValue():match('(%+?%d+)'),
                            m_textCtrl_sms:GetValue(),
                            m_comboBox_encoding:GetValue())
        --first send "AT+CMGS=xx\n"
        local msg = send_AT_CMD_REQ_and_wait_CNF
        {
            msgtype="AT_CMD_REQ",
            at_type="AT_CMGS_PDU",
            at_cmd=at1,
            pause_detector = true,--pause the detector
            from = task.id(),
        }
        print("AT_CMGF_SET_PDU result:",atcmd.repr(msg.reply))
        --if phone do not return ">",we think it is error and abort send sms
        if string.find(msg.reply,">")==nil then
            wx.wxMessageBox(string.format("Send sms failed,phone return:%s",atcmd.repr(msg.reply)),
                            "Phonecom",
                            wx.wxOK + wx.wxICON_EXCLAMATION,
                            wx.NULL)
            
            return
        end
        
        --then we send the sms pdu data
        local msg = send_AT_CMD_REQ_and_wait_CNF
        {
            msgtype="AT_CMD_REQ",
            at_type="AT_CMGS_PDU",
            at_cmd=at2,
            pause_detector = false,--resume the detector
            timeout = 15000,--send sms may be slow...
            from = task.id(),
        }
        print("AT_CMGF_SET_PDU result:",atcmd.repr(msg.reply))
        local send_sms_ok = (string.find(tostring(msg.reply),"OK")~=nil)
        local msg
        if send_sms_ok then
            msg = "send sms ok!"
        else
            msg = "send sms fail!"
        end
        wx.wxMessageBox(msg,
                        "Phonecom",
                        wx.wxOK + wx.wxICON_EXCLAMATION,
                        wx.NULL)
        
    end
    mainframe_set_msgco_and_go(self,sendsms)
end

function mainframe_on_comboBox_encoding_update(self,msg)
    self.config.os_default_encoding = self.m_comboBox_encoding:GetValue()
end

function mainframe_on_textCtrl_sms_update(self,event)
    local cd = iconv.new("UTF-16BE" .. "//TRANSLIT", self.config.os_default_encoding)
    local user_data_ucs2, err = cd:iconv(self.m_textCtrl_sms:GetValue())
    assert(user_data_ucs2)
    local len = user_data_ucs2:len()/2
    self.sms_too_long = len> 70 --70char/sms
    self.m_staticText_charcount:SetLabel(string.format("%d char",len))
    local color
    if (self.sms_too_long) then
        color = wx.wxRED
    else
        color = wx.wxBLACK
    end
    self.m_staticText_charcount:SetForegroundColour(color)
    self:refresh_controls_enable()
end

function mainframe_on_textCtrl_phonenum_update(self,event)
    --get the part string we want to search in contacts list
    local function get_part_input(s,ci)
        local split_char = ",; "
        if split_char:find(s:sub(ci,ci))~=nil then
            return
        end
        local bi=ci
        local ei=ci
        while (ei <= #s) do
            if (split_char:find(s:sub(ei+1,ei+1))==nil) then
                ei = ei + 1
            else
                break
            end
        end
        
        while (bi>=1) do
            if (split_char:find(s:sub(bi-1,bi-1))==nil) then
                bi = bi-1
            else
                break
            end
        end
        print(s,bi,ei,ci)
        return s:sub(bi,ei),bi,ei
    end
    
    --because GetInsertionPoint can not give result
    --lua string can use,so I just get the part input in the end
    local function get_part_input_end(s)
        local split_char = ",; "
        local ei = s:len()
        local bi = ei
        --if it is "" or the last charactor is split char,not search
        if ei==0 or split_char:find(s:sub(ei,ei))~=nil then
            return
        end
        
        while (bi>=1) do
            if (split_char:find(s:sub(bi-1,bi-1))==nil) then
                bi = bi-1
            else
                break
            end
        end
        --print(s,bi,ei,ci)
        return s:sub(bi,ei),bi,ei
    end
    
    local s,bi,ei = get_part_input_end(self.m_textCtrl_phonenum:GetValue(),
            self.m_textCtrl_phonenum:GetInsertionPoint())
    --print(s,bi,ei,self.m_textCtrl_phonenum:GetInsertionPoint(),self.m_textCtrl_phonenum:GetLastPosition())
    --print(prettytostring(self.contactsdb:search_cache(s)))
    local r = self.contactsdb:search_cache(s)
    if (s and #r>0) then
        self.contact_listbox:Set(r)
        self.contact_listbox:Show()
        self.m_panel_main:Layout()
        
        self:Connect(self.contact_listbox:GetId(),
            wx.wxEVT_COMMAND_LISTBOX_SELECTED,
            function(event)
                print(self.contact_listbox:GetSelections())
                local n,selections = self.contact_listbox:GetSelections()
                if n > 0 then
                    local i = selections[1]
                    --replace with selection
                    local w = self.m_textCtrl_phonenum:GetValue()
                    self.m_textCtrl_phonenum:SetValue(w:sub(1,bi-1)..r[i+1]..w:sub(ei+1)..",")
                    self.m_textCtrl_phonenum:SetInsertionPointEnd()
                end
                self.contact_listbox:Hide()
                self.m_panel_main:Layout()
                self:Disconnect(self.contact_listbox:GetId(),wx.wxEVT_COMMAND_LISTBOX_SELECTED)
                self.m_textCtrl_phonenum:SetFocus()
            end)
        
    else
        self.contact_listbox:Hide()
        self.m_panel_main:Layout()
    end
end

function mainframe_on_textCtrl_phonenum_kill_focus(self,event)
    self.contact_listbox:Hide()
    self.m_panel_main:Layout()
end

function mainframe_msg_handle(self,msg)
    if (msg.msgtype=="SEARCH_CONNECTED_COM_CNF") then
        self.connected_rs232_port = msg.port or ""
        --print("connected port:",self.connected_rs232_port)
        local status
        if msg.port then
            status = string.format("connected:%s",tostring(msg.port))
            --become connected,so we need to init the phone
            mainframe_init_phone(self)
        else
            status = "diconnected"
        end
        self.m_statusBar:SetStatusText(status)
    elseif (msg.msgtype=="CONN_STATUS_IND") then
        if not msg.connected then
            self.connected_rs232_port=""
            self.phone_init_finished = false
            
            self.m_statusBar:SetStatusText("diconnected")
        end
    else -- else,we give the msg to msgco to handle
        if (self.msgco~=nil and (coroutine.status(self.msgco)=="suspended")) then
            local resume_ok,err = coroutine.resume(self.msgco,msg)
            print(resume_ok,err)
            if (not resume_ok) then print(debug.traceback(self.msgco)) end
            print("after handle msg:",coroutine.status(self.msgco))
        else
            print("this msg have no handler...")
        end
    end
    mainframe_refresh_controls_enable(self)
end

function mainframe_import_all_contacts_co(self)
    local contacts = {}
    --general err dlg
    local function err_dlg(err)
        local msg = err or ""
        wx.wxMessageBox(string.format("Import failed.%s",msg),
                        "Phonecom",
                        wx.wxOK + wx.wxICON_EXCLAMATION,
                        wx.NULL)
    end
    
    --firstly set charset to UCS2
    local msg = send_AT_CMD_REQ_and_wait_CNF
    {
        msgtype="AT_CMD_REQ",
        at_type="AT_CSCS",
        at_cmd=atcmd.AT_CSCS("UCS2"),
        pause_detector = true,--notice:we pause here
        from = task.id(),
    }
    if string.find(msg.reply,"OK")==nil then
        err_dlg(string.format("AT+CSCS err:%s",atcmd.repr(msg.reply)))
        return
    end
    
    --then set current storage to SM
    local msg = send_AT_CMD_REQ_and_wait_CNF
    {
        msgtype="AT_CMD_REQ",
        at_type="AT_CPBS",
        at_cmd=atcmd.AT_CPBS("SM"),
        from = task.id(),
    }
    if string.find(msg.reply,"OK")==nil then
        err_dlg(string.format("err:%s",atcmd.repr(msg.reply)))
        return
    end
    --then query the capacity of phonebook in SM
    local msg = send_AT_CMD_REQ_and_wait_CNF
    {
        msgtype="AT_CMD_REQ",
        at_type="AT_CPBS",
        at_cmd=atcmd.AT_CPBS(),
        from = task.id(),
    }
    local storage,used,all = atcmd.get_storage_cap_AT_CPBS(msg.reply)
    self.sm_used = tonumber(used)
    self.sm_all = tonumber(all)
    if (self.sm_used==nil or self.sm_all==nil) then
        err_dlg("err:can not get SIM storage info")
        return
    end
    --then we begin to read all phonebook item in SIM
    local cd = iconv.new(self.config.os_default_encoding .. "//TRANSLIT", "UTF-16BE")
    for i = 1,self.sm_all do
        self.m_statusBar:SetStatusText(string.format("read SIM contact:%d/%d",tostring(i),self.sm_all),1)
        local msg = send_AT_CMD_REQ_and_wait_CNF
        {
            msgtype="AT_CMD_REQ",
            at_type="AT_CPBR",
            at_cmd=atcmd.AT_CPBR(i),
            from = task.id(),
        }
        print("receive:"..atcmd.repr(msg.reply))
        local index,number,ntype,name = atcmd.get_number_and_name_AT_CPBR(msg.reply)
        if name then
            --print("cpbr :",index,number,ntype,math.floor(tonumber(ntype)%128/16))
            if math.floor(tonumber(ntype)%128/16)==1 then number = "+"..number end
            local name_defaultenc, err = cd:iconv(name)
            --print(number,name_defaultenc)
            --print(atcmd.repr(name_defaultenc),atcmd.repr(name))
            contacts[#contacts+1] = {number=number,name_ucs2 = name,name_defaultenc = name_defaultenc}
        end
    end
    
    --then set current storage to ME
    local msg = send_AT_CMD_REQ_and_wait_CNF
    {
        msgtype="AT_CMD_REQ",
        at_type="AT_CPBS",
        at_cmd=atcmd.AT_CPBS("ME"),
        from = task.id(),
    }
    if string.find(msg.reply,"OK")==nil then
        err_dlg(string.format("err:%s",atcmd.repr(msg.reply)))
        return
    end
    --then query the capacity of phonebook in ME
    local msg = send_AT_CMD_REQ_and_wait_CNF
    {
        msgtype="AT_CMD_REQ",
        at_type="AT_CPBS",
        at_cmd=atcmd.AT_CPBS(),
        from = task.id(),
    }
    local storage,used,all = atcmd.get_storage_cap_AT_CPBS(msg.reply)
    self.me_used = tonumber(used)
    self.me_all = tonumber(all)
    print("me_used:",self.me_used,"me_all",self.me_all)
    if (self.sm_used==nil or self.sm_all==nil) then
        err_dlg("err:can not get ME storage info")
        return
    end
    
    --then we begin to read all phonebook item in ME
    local cd = iconv.new(self.config.os_default_encoding .. "//TRANSLIT", "UTF-16BE")
    for i = 1,self.me_all do
        self.m_statusBar:SetStatusText(string.format("read ME contact:%d/%d",tostring(i),self.me_all),1)
        local msg = send_AT_CMD_REQ_and_wait_CNF
        {
            msgtype="AT_CMD_REQ",
            at_type="AT_CPBR",
            at_cmd=atcmd.AT_CPBR(i),
            from = task.id(),
        }
        --print("receive:"..atcmd.repr(msg.reply))
        local index,number,ntype,name = atcmd.get_number_and_name_AT_CPBR(msg.reply)
        if name then
            --print("cpbr :",index,number,ntype,math.floor(tonumber(ntype)%128/16))
            if math.floor(tonumber(ntype)%128/16)==1 then number = "+"..number end
            local name_defaultenc, err = cd:iconv(name)
           -- print(number,name_defaultenc)
            contacts[#contacts+1] = {number=number,name_ucs2 = name,name_defaultenc = name_defaultenc}
        end
    end
    
    
    --resume detector
    local msg = send_AT_CMD_REQ_and_wait_CNF
    {
        msgtype="AT_CMD_REQ",
        at_type="AT_CSCS",
        at_cmd=atcmd.AT_CSCS("UCS2"),
        pause_detector = false,
        from = task.id(),
    }
    
    self.m_statusBar:SetStatusText("",1)
    
    --[[
    for i,c in ipairs(contacts) do
        print(i,c.name_defaultenc)
    end
    --]]
    
    return contacts
end

----contactsdlg class extend
function contactsdlg_on_button_import_contacts(self,mainframe,event)
    --here is also because of wxlua bug
    --TODO:modify to mainframe.config and no need of "local config"
    self.config = mainframe.config
    self.m_statusBar = mainframe.m_statusBar
    
    mainframe:set_msgco_and_go(function ()
            local contacts = mainframe_import_all_contacts_co(mainframe)
            self.contactsdb:replace_cache(contacts)
        end)
end
function contactsdlg_init(self,mainframe)
    local htmlTextPage =
    [[<html>
<head>
<meta content="text/html; charset=ISO-8859-1"
http-equiv="content-type">
<title></title>
</head>
<body>
<DIV align="center"><TABLE cellspacing="2" cellpadding="5" border="1">
<TR><TD>name</TD>
<TD>phone number</TD></TR>
</TABLE></DIV>
</body>
</html>
]]
    local html = wx.wxLuaHtmlWindow(self.m_panel_contacts)
    html:SetPage(htmlTextPage)
    local sizer_panel = wx.wxBoxSizer(wx.wxVERTICAL)
    sizer_panel:Add(html, 1, wx.wxGROW + wx.wxALL, 1)
    self.m_panel_contacts:SetSizer(sizer_panel)
end

----create mainframe object
function phonecom_mainframe()
    ----xml resource
    -- xml style resources (if present)
    local xmlResource = wx.wxXmlResource()
    xmlResource:InitAllHandlers()
    local xrcFilename = "phonecom.xrc"
    
    -- try to load the resource and ask for path to it if not found
    while not xmlResource:Load(xrcFilename) do
        -- must unload the file before we try again
        xmlResource:Unload(xrcFilename)
    
        wx.wxMessageBox("Error loading xrc resources, please choose the path to 'calculator.xrc'.",
                        "Calculator",
                        wx.wxOK + wx.wxICON_EXCLAMATION,
                        wx.NULL)
        local fileDialog = wx.wxFileDialog(wx.NULL,
                                           "Open 'phonecom.xrc' resource file",
                                           "",
                                           "phonecom.xrc",
                                           "XRC files (*.xrc)|*.xrc|All files (*)|*",
                                            wx.wxOPEN + wx.wxFILE_MUST_EXIST)
    
        if fileDialog:ShowModal() == wx.wxID_OK then
            xrcFilename = fileDialog:GetPath()
        else
            return -- quit program
        end
    end
    
    --this is mainframe
    local mainframe = wx.wxFrame()
    
    --remember the xmlResource
    mainframe.xmlResource = xmlResource
    
    --load mainframe from xrc
    if not xmlResource:LoadFrame(mainframe, wx.NULL, "mainframe") then
        wx.wxMessageBox("Error loading xrc resources!",
                        "Phonecom",
                        wx.wxOK + wx.wxICON_EXCLAMATION,
                        wx.NULL)
        return -- quit program
    end
    
    --get wxWindow ID values in xrc
    mainframe.m_statusBar = (wx.wxFindWindowByName("m_statusBar",mainframe)):DynamicCast("wxStatusBar")
    mainframe.m_button_contacts = (wx.wxFindWindowByName("m_button_contacts",mainframe)):DynamicCast("wxButton")
    mainframe.m_button_smslog = (wx.wxFindWindowByName("m_button_smslog",mainframe)):DynamicCast("wxButton")
    mainframe.m_button_sendsms = (wx.wxFindWindowByName("m_button_sendsms",mainframe)):DynamicCast("wxButton")
    mainframe.m_textCtrl_phonenum = (wx.wxFindWindowByName("m_textCtrl_phonenum",mainframe)):DynamicCast("wxTextCtrl")
    mainframe.m_textCtrl_sms = (wx.wxFindWindowByName("m_textCtrl_sms",mainframe)):DynamicCast("wxTextCtrl")
    mainframe.m_comboBox_encoding = (wx.wxFindWindowByName("m_comboBox_encoding",mainframe)):DynamicCast("wxComboBox")
    mainframe.m_staticText_charcount = (wx.wxFindWindowByName("m_staticText_charcount",mainframe)):DynamicCast("wxStaticText")
    mainframe.m_listBox_contacts =  (wx.wxFindWindowByName("m_listBox_contacts",mainframe)):DynamicCast("wxListBox")
    mainframe.m_panel_main = (wx.wxFindWindowByName("m_panel_main",mainframe)):DynamicCast("wxPanel")
    mainframe.m_panel_smslog = (wx.wxFindWindowByName("m_panel_smslog",mainframe)):DynamicCast("wxPanel")
    ----extend class
    mainframe.create_subtask = mainframe_create_subtask
    mainframe.set_msgco_and_go = mainframe_set_msgco_and_go
    mainframe.refresh_controls_enable = mainframe_refresh_controls_enable
    mainframe.import_all_contacts_co = mainframe_import_all_contacts_co
    
    mainframe.connected_rs232_port = "" --"" means not connected
    mainframe.sms_too_long = false
    -- TODO:after wxlua fixed the bug,will be modified to "mainframe.phone_id"
    mainframe.phone_id = "" 
    mainframe.phone_init_finished = false
    --self_contact_listbox = mainframe.m_listBox_contacts
    
    local htmlTextPage =
    [[<html>
        <head>
        <title>sms log</title>
        </head>
        <body>
            <center>log no loaded</center>
        </body>
    </html>]]
    local html = wx.wxLuaHtmlWindow(mainframe.m_panel_smslog)
    html:SetPage(htmlTextPage)
    local sizer_panel = wx.wxBoxSizer(wx.wxVERTICAL)
    sizer_panel:Add(html, 1, wx.wxGROW + wx.wxALL, 1)
    mainframe.m_panel_smslog:SetSizer(sizer_panel)
    
    mainframe.m_textCtrl_phonenum:SetFocus()
    
    --contact listbox
    --[[
    local r = mainframe.m_textCtrl_phonenum:GetRect()
    local p = wx.wxPoint(r:GetLeft(),r:GetBottom())
    mainframe.contact_listbox = wx.wxListBox(
        mainframe,
        wx.wxID_ANY,
        p,
        wx.wxSize(200,300),
        {},
        wx.wxLB_SINGLE + wx.wxLB_ALWAYS_SB,
        wx.wxDefaultValidator,
        "listBox");
    mainframe.contact_listbox:SetBackgroundColour(wx.wxColour(244,247,177))
    --]]
    mainframe.contact_listbox = mainframe.m_listBox_contacts
    mainframe.contact_listbox:Hide()
    mainframe.m_panel_main:Layout()
    --mainframe:SetAutoLayout(true)
    --mainframe.m_panel_main:SetAutoLayout(true)
    
    --config
    local default_config = 
    {
        os_default_encoding = "UTF-8",
        port_name_prefix = "auto",
    }
    mainframe.config = config.new("CONFIG",default_config)
    
    --apply config
    mainframe.m_comboBox_encoding:SetValue(mainframe.config.os_default_encoding)

    ----events
    --idle event,continue to find message to handle again and again
    --[[
    mainframe:Connect(wx.wxEVT_IDLE,
        function(event)
            mainframe_on_idle(mainframe,event)
        end)
    --]]
    --in linux,wxEVT_IDLE only happy when mouse move in mainframe
    --so I create a timer for doing mainframe_on_idle
    local timer = wx.wxTimer(mainframe)
    mainframe:Connect(wx.wxEVT_TIMER,
        function(event)
            mainframe_on_idle(mainframe,event)
        end)
    timer:Start(400)
    --we should remember this timer,otherwise it may be GCed and lost...
    mainframe.msg_timer = timer
    
    mainframe:Connect(mainframe.m_button_contacts:GetId(),
        wx.wxEVT_COMMAND_BUTTON_CLICKED,
        function(event)
            mainframe_on_button_contacts(mainframe,event)
        end)
    
    mainframe:Connect(mainframe.m_button_smslog:GetId(),
        wx.wxEVT_COMMAND_BUTTON_CLICKED,
        function(event)
            mainframe_on_button_smslog(mainframe,event)
        end)
    
    mainframe:Connect(mainframe.m_button_sendsms:GetId(),
        wx.wxEVT_COMMAND_BUTTON_CLICKED,
        function(event)
            mainframe_on_button_sendsms(mainframe,event)
        end)
    
    mainframe:Connect(mainframe.m_comboBox_encoding:GetId(),
        wx.wxEVT_COMMAND_TEXT_UPDATED,
        function(event)
            mainframe_on_comboBox_encoding_update(mainframe,event)
        end)
    
    mainframe:Connect(mainframe.m_textCtrl_sms:GetId(),
        wx.wxEVT_COMMAND_TEXT_UPDATED,
        function(event)
            mainframe_on_textCtrl_sms_update(mainframe,event)
        end)
        
    mainframe:Connect(mainframe.m_textCtrl_phonenum:GetId(),
        wx.wxEVT_COMMAND_TEXT_UPDATED,
        function(event)
            mainframe_on_textCtrl_phonenum_update(mainframe,event)
        end)
    
    mainframe:Connect(mainframe.m_textCtrl_phonenum:GetId(),
        wx.wxEVT_KILL_FOCUS,
        function(event)
            mainframe_on_textCtrl_phonenum_kill_focus(mainframe,event)
        end)
    
    ----dialogs
    
    --contactsdlg
    local contactsdlg = wx.wxDialog()
    --load from xrc
    if not mainframe.xmlResource:LoadDialog(contactsdlg, mainframe, "contactsdlg") then
        wx.wxMessageBox("Error loading xrc resources!",
                        "Phonecom",
                        wx.wxOK + wx.wxICON_EXCLAMATION,
                        wx.NULL)
        return -- quit program
    end
    --get component from XRC
    contactsdlg.m_button_import_contacts = (wx.wxFindWindowByName("m_button_import_contacts",contactsdlg)):DynamicCast("wxButton")
    contactsdlg.m_panel_contacts = (wx.wxFindWindowByName("m_panel_contacts",contactsdlg)):DynamicCast("wxPanel")
    --event
    contactsdlg:Connect(contactsdlg.m_button_import_contacts:GetId(),
        wx.wxEVT_COMMAND_BUTTON_CLICKED,
        function(event)
            contactsdlg_on_button_import_contacts(contactsdlg,mainframe,event)
        end)
    --init contacts html window
    contactsdlg_init(contactsdlg,mainframe)
    
    --remember it
    mainframe.contactsdlg = contactsdlg
    
    --smslogdlg
    mainframe.smslogdlg = wx.wxDialog()
    --load from xrc
    if not mainframe.xmlResource:LoadDialog(mainframe.smslogdlg, mainframe, "smslogdlg") then
        wx.wxMessageBox("Error loading xrc resources!",
                        "Phonecom",
                        wx.wxOK + wx.wxICON_EXCLAMATION,
                        wx.NULL)
        return -- quit program
    end
    
    return mainframe
end

function main()
    -- create the frame window
    local frame = phonecom_mainframe()
    
    -- create sub task,such as conndetector/atworker
    frame:create_subtask()
    
    -- show the frame window
    frame:Show(true)
end

main()

-- Call wx.wxGetApp():MainLoop() last to start the wxWidgets event loop,
-- otherwise the wxLua program will exit immediately.
-- Does nothing if running from wxLua, wxLuaFreeze, or wxLuaEdit since the
-- MainLoop is already running or will be started by the C++ program.
wx.wxGetApp():MainLoop()
